
//
// 121107 - AH - Created.
//

package org.japril.jhut.framework;

/**
 * <p>
 * </p>
 * @author Arne Halvorsen (AH)
 */
public final class Assertions
{
  private Assertions(){} // Utility pattern dictates private constructor.
  
  //
  // Assertion.
  //
  
  private static boolean c_ignoreAssert=false;
  
  /**
   * <p>
   *   Sets to ignore assertion or not.
   * </p>
   * @param v {@code true} if to ignore, {@code false} not to (default). 
   */
  public static void setIgnoreAssertion(boolean v){ c_ignoreAssert=v; }
  
  /**
   * <p>
   *   Tells if ignore assertion or not.
   * </p>
   * @return {@code true} if does, {@code false} else.
   */
  public static boolean getIgnoreAssertion(){ return c_ignoreAssert; }
  
  /**
   * <p>
   *   Force assertion failure, of use for test being developed.
   * </p>
   * @param msg Message, may be {@code null}.
   */
  public static void fail(String msg)
  {
    if (msg==null) throw new AssertException("Forced fail");
    else           throw new AssertException(msg);
  }
  
  /**
   * <p>
   *   Asserts not null.
   * </p> 
   * @param p  Pointer not to be {@code null}.
   * @throws AssertException If {@code p==null} 
   */
  public static final void assertNotNull(Object p){ assertNotNull(null, p); }
  
  /**
   * <p>
   *   Asserts not null.
   * </p>
   * @param name Name on object asserted to exist, may be {@code null}. 
   * @param p    Pointer not to be {@code null}.
   * @throws AssertException If {@code p==null} 
   */
  public static final void assertNotNull(String name, Object p)
  {
    if (c_ignoreAssert) return;
    
    if (p==null)
    {
      if (name==null) throw new NullPointerException("Is null");
      else            throw new NullPointerException(name+" is null");
    }
  }
  
  /**
   * <p>
   *   Asserts null.
   * </p>
   * @param p Pointer to be {@code null}.
   * @throws AssertException If {@code p!=null} 
   */
  public static final void assertNull(Object p){ assertNull(null, p); }
  
  /**
   * <p>
   *   Asserts null.
   * </p>
   * @param name Name on object asserted not to exist, may be {@code null}.
   * @param p    Pointer to be {@code null}.
   * @throws AssertException If {@code p!=null} 
   */
  public static final void assertNull(String name, Object p)
  {
    if (c_ignoreAssert) return;
    
    if (p!=null)
    {
      if (name==null) throw new AssertException("Not null");
      else            throw new AssertException(name+" not null");
    }
  }
  
  /**
   * <p>
   *   Asserts {@code true}.
   * </p>
   * @param v Actually value of statement.
   * @throws AssertException If {@code v==false}.
   */
  public static final void assertTrue(boolean v){ assertTrue(null, v); }
  
  /**
   * <p>
   *   Asserts {@code true}.
   * </p>
   * @param s Statement asserted to be {@code true}, may be {@code null}.
   * @param v Actually value of statement.
   * @throws AssertException If {@code v==false}. 
   */
  public static final void assertTrue(String s, boolean v)
  {
    if (c_ignoreAssert) return;
    
    if (!v)
    {
      if (s==null) throw new AssertException("Not true");
      else         throw new AssertException(s+" not true");
    }
  }
  
  /**
   * <p>
   *   Asserts equals.
   * </p>
   * @param expected Expected value.
   * @param actually Actually value.
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}.
   */
  public static final void assertEquals(Object expected, Object actually)
  {
    assertEquals(null, expected, actually);
  }
  
  /**
   * <p>
   *   Asserts equals.
   * </p>
   * @param name     Name on object being test, may be {@code null}.
   * @param expected Expected value.
   * @param actually Actually value.
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}.
   */
  public static final void assertEquals(String name, Object expected,
    Object actually)
  {
    if (c_ignoreAssert) return;
    
    if (expected==null)
    {
      throw new NullPointerException("expected");
    }
    if (actually==null)
    {
      throw new NullPointerException("actually");
    }
    
    if (expected==actually) return;
    
    if (!expected.equals(actually))
    {
      throw new AssertException(name, expected, actually);
    }
    if (!actually.equals(expected))
    {
      throw new AssertException(name, expected, actually);
    }
  }
  
  /**
   * <p>
   *   Asserts {@code float} value.
   * </p>
   * @param name     Name on value being test, may be {@code null}.
   * @param expected Expected value.
   * @param actually Actually value.
   * @param delta    If absolute difference between {@code expected} and
   *                 {@code actually} 
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}. 
   */
  public static final void assertEquals(float expected, float actually, 
    float delta)
  {
    assertEquals(null, expected, actually, delta);
  }
  
  /**
   * <p>
   *   Asserts {@code float} value.
   * </p>
   * @param name     Name on value being test, may be {@code null}.
   * @param expected Expected value.
   * @param actually Actually value.
   * @param delta    If absolute difference between {@code expected} and
   *                 {@code actually} 
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}. 
   */
  public static final void assertEquals(String name, float expected, 
    float actually, float delta)
  {
    if (c_ignoreAssert) return;
    
    if (delta<0.0f)
    {
      throw new IllegalArgumentException("delta<0.0 : "+delta);
    }
    
    float diff=expected-actually;
    diff=diff<0.0f ? -diff : diff;
    if (diff>delta)
    {
      throw new AssertException(name, expected, actually);
    }
  }
  
  /**
   * <p>
   *   Asserts {@code float} value.
   * </p>
   * <p>
   *   Using a delta of {@code 1e-6}.
   * </p>
   * @param expected Expected value.
   * @param actually Actually value. 
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}. 
   */
  public static final void assertEquals(float expected, float actually)
  {
    assertEquals(null, expected, actually, 1e-6f);
  }
  
  /**
   * <p>
   *   Asserts {@code float} value.
   * </p>
   * <p>
   *   Using a delta of {@code 1e-6}.
   * </p>
   * @param name     Name on value being test, may be {@code null}.
   * @param expected Expected value.
   * @param actually Actually value. 
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}. 
   */
  public static final void assertEquals(String name, float expected,
    float actually)
  {
    assertEquals(name, expected, actually, 1e-6f);
  }
  
  /**
   * <p>
   *   Asserts {@code double} value.
   * </p>
   * @param name     Name on value being test, may be {@code null}.
   * @param expected Expected value.
   * @param actually Actually value.
   * @param delta    If absolute difference between {@code expected} and
   *                 {@code actually} 
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}. 
   */
  public static final void assertEquals(double expected, double actually, 
    double delta)
  {
    assertEquals(null, expected, actually, delta);
  }
  
  /**
   * <p>
   *   Asserts {@code double} value.
   * </p>
   * @param name     Name on value being test, may be {@code null}.
   * @param expected Expected value.
   * @param actually Actually value.
   * @param delta    If absolute difference between {@code expected} and
   *                 {@code actually} 
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}. 
   */
  public static void assertEquals(String name, double expected, double actually, 
    double delta)
  {
    if (c_ignoreAssert) return;
    
    if (delta<0.0)
    {
      throw new IllegalArgumentException("delta<0.0 : "+delta);
    }
    
    double diff=expected-actually;
    diff=diff<0.0 ? -diff : diff;
    if (diff>delta)
    {
      throw new AssertException(name, expected, actually);
    }
  }
  
  /**
   * <p>
   *   Asserts {@code double} value.
   * </p>
   * <p>
   *   Using a delta of {@code 1e-6}.
   * </p>
   * @param expected Expected value.
   * @param actually Actually value. 
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}. 
   */
  public static final void assertEquals(double expected, double actually)
  {
    assertEquals(null, expected, actually, 1e-6);
  }
  
  /**
   * <p>
   *   Asserts {@code double} value.
   * </p>
   * <p>
   *   Using a delta of {@code 1e-6}.
   * </p>
   * @param name     Name on value being test, may be {@code null}.
   * @param expected Expected value.
   * @param actually Actually value. 
   * @throws AssertException If {@code expected} does not equals 
   *         {@code actually}. 
   */
  public static final void assertEquals(String name, double expected, 
    double actually)
  {
    assertEquals(name, expected, actually, 1e-6);
  }
  
  /**
   * <p>
   *   Asserts an objects 
   *   {@link Object#toString()} method returns a given
   *   {@link String}.
   * </p>
   * @param name     Name on object being test, may be {@code null}. 
   * @param expected Expected 
   *                 {@link String}.
   * @param o        Object.
   */
  public static final void assertToString(String expected, Object o)
  {
    assertToString(null, expected, o);
  }
  
  /**
   * <p>
   *   Asserts an objects 
   *   {@link Object#toString()} method returns a given
   *   {@link String}.
   * </p>
   * @param expected Expected 
   *                 {@link String}.
   * @param o        Object.
   */
  public static final void assertToString(String name, String expected, 
    Object o)
  {
    if (c_ignoreAssert) return;
    
    if (expected==null)
    {
      throw new NullPointerException("expected");
    }
    if (o==null)
    {
      throw new NullPointerException("o");
    }
    
    String s=o.toString();
    if (s==null)
    {
      throw new AssertException("toString() returns null");
    }
    
    if (!s.equals(expected))
    {
      throw new AssertException(name, expected, s);
    }
  }
  
  /**
   * <p>
   *   Asserts type of a given object is a given concrete type (not only a 
   *   generalization of the expected type).
   * </p>
   * @param expected Expected type.
   * @param o        Object which type to test.
   */
  public static final void assertConcreteType(Class<?> expected, Object o)
  {
    assertConcreteType(null, expected, o);
  }
  
  /**
   * <p>
   *   Asserts type of a given object is a given concrete type (not only a 
   *   generalization of the expected type).
   * </p>
   * @param name     Name of object which type is tested. May be {@code null}.
   * @param expected Expected type.
   * @param o        Object which type to test.
   */
  public static final void assertConcreteType(String name, Class<?> expected,
    Object o)
  {
    if (c_ignoreAssert) return;
    
    if (o==null)
    {
      throw new NullPointerException("o");
    }
    if (expected==null)
    {
      throw new NullPointerException("expected");
    }
    
    Class<?> actually=o.getClass();
    
    if (expected!=actually)
    {
      if (name!=null)
      {
        throw new AssertException("Expected type: "+expected.getName()+
          " but got type: "+actually.getName());
      }
      else
      {
        throw new AssertException("Expected type: "+expected.getName()+
          " for "+name+" but got type: "+actually.getName());
      }
    }
  }
  
}
